﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using Assist;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using YArchitech.Controls;
using YJKArchUtils.Utils;
using YJKRevitBase.WinForm;

namespace YJKRevitWallModule.WallModule.CreateWall
{
	public class DrawWallManager
	{
		[DllImport("user32.dll", EntryPoint = "SendMessageA")]
		public static extern int SendMessage(IntPtr hwnd, int wMsg, IntPtr wParam, IntPtr lParam);

		public DrawWallManager(ExternalCommandData commandData)
		{
			this.m_commandData = commandData;
			this.m_uiDoc = commandData.Application.ActiveUIDocument;
			this.m_doc = this.m_uiDoc.Document;
			if (DrawWallManager._hWndRevit == null)
			{
				DrawWallManager._hWndRevit = new WindowHandle(Process.GetCurrentProcess().MainWindowHandle);
			}
			this.m_lstResWallType = this.GetAllWallTypes();
		}

		public Result DrawWallLoop(string strWallFSType = null)
		{
			DrawWallForm drawWallForm = null;
			try
			{
				drawWallForm = new DrawWallForm(this.m_doc, this.m_lstResWallType, strWallFSType);
				drawWallForm.Show(DrawWallManager._hWndRevit);
			}
			catch (Exception)
			{
				if (drawWallForm != null)
				{
					drawWallForm.Close();
				}
				return Autodesk.Revit.UI.Result.Failed;
			}
			int wMsg = 7;
			DrawWallManager.SendMessage(DrawWallManager._hWndRevit.Handle, wMsg, IntPtr.Zero, IntPtr.Zero);
			JigLineOperator jigLineOperator = new JigLineOperator(this.m_doc, drawWallForm, this.m_commandData);
			TransactionGroup transactionGroup = new TransactionGroup(this.m_doc, "Create Insulation Layer");
			Result result;
			try
			{
				transactionGroup.Start();
				using (YRevitJigExtend hyjigExtend = new YRevitJigExtend(this.m_uiDoc, drawWallForm))
				{
					hyjigExtend.SetPromptState("", false, true);
					try
					{
						List<UseData> list = new List<UseData>();
						while (drawWallForm.m_isExist)
						{
							if (this.bisEnd)
							{
								jigLineOperator.ClearSelectPt();
							}
							try
							{
								this.getPointLoop(jigLineOperator, hyjigExtend, drawWallForm, ref list);
							}
							catch (Exception)
							{
								if (drawWallForm.m_isChangeMaterial)
								{
									drawWallForm.ChangeMaterialType();
									drawWallForm.m_isChangeMaterial = false;
									continue;
								}
							}
							if (list.Count == 0)
							{
								drawWallForm.Close();
								break;
							}
							this.DrawWall(list);
							jigLineOperator.deleteDetailCures();
							this.bisEnd = true;
							list.Clear();
						}
						transactionGroup.Assimilate();
						result = Autodesk.Revit.UI.Result.Succeeded;
					}
					catch (Exception ex)
					{
                        if (1 == (int)transactionGroup.GetStatus())
						{
							transactionGroup.RollBack();
						}
						jigLineOperator.deleteDetailCures();
						drawWallForm.Close();
						YJKMessageBox.Show(ex.Message);
						result = Autodesk.Revit.UI.Result.Succeeded;
					}
				}
			}
			catch (Exception)
			{
                if (1 == (int)transactionGroup.GetStatus())
				{
					transactionGroup.RollBack();
				}
				jigLineOperator.deleteDetailCures();
				result = Autodesk.Revit.UI.Result.Failed;
			}
			return result;
		}

		private Result DrawWall(List<UseData> lstInputData)
		{
			double num = 0.0;
			double num2 = 0.0;
			if (lstInputData.Count > 1)
			{
				this.MergeSameWallInfo(ref lstInputData);
			}
			Transaction transaction = new Transaction(this.m_doc, "Create Wall");
			transaction.Start();
			foreach (UseData useData in lstInputData)
			{
				if (useData.strWallOffset != "0")
				{
					num2 = Common.MMToFeet(double.Parse(useData.strWallOffset));
				}
				try
				{
					this.GetWallHeight(useData, ref num);
					Wall wall = Wall.Create(this.m_doc, useData.line, useData.wallTypeId, this.m_doc.ActiveView.GenLevel.Id, num, num2, false, false);
					if (wall != null)
					{
						if (wall.get_Parameter(BuiltInParameter.WALL_BASE_OFFSET) != null)
						{
							wall.get_Parameter(BuiltInParameter.WALL_BASE_OFFSET).Set(num2);
						}
						if (wall.get_Parameter(BuiltInParameter.WALL_HEIGHT_TYPE) != null)
						{
							wall.get_Parameter(BuiltInParameter.WALL_HEIGHT_TYPE).Set(this.m_TopLevel.Id);
						}
						if (wall.get_Parameter(BuiltInParameter.WALL_TOP_OFFSET) != null)
						{
							wall.get_Parameter(BuiltInParameter.WALL_TOP_OFFSET).Set(this.m_TopLevelOffsetVal);
						}
						if (wall.get_Parameter(BuiltInParameter.WALL_KEY_REF_PARAM) != null)
						{
							wall.get_Parameter(BuiltInParameter.WALL_KEY_REF_PARAM).Set(this.GetLocationType(useData.location));
						}
						KeyValuePair<string, string> strMaterial2FillName = useData.strMaterial2FillName;
						if (strMaterial2FillName.Key == "钢筋混凝土" && wall.get_Parameter(BuiltInParameter.WALL_STRUCTURAL_SIGNIFICANT) != null)
						{
							wall.get_Parameter(BuiltInParameter.WALL_STRUCTURAL_SIGNIFICANT).Set(1);
						}
						if (wall.WallType.get_Parameter(BuiltInParameter.FUNCTION_PARAM) != null)
						{
							wall.WallType.get_Parameter(BuiltInParameter.FUNCTION_PARAM).Set(this.GetPurposeType(useData.strPurpose));
						}
					}
				}
				catch (Exception)
				{
					transaction.RollBack();
					return Autodesk.Revit.UI.Result.Failed;
				}
			}
			transaction.Commit();
			return Autodesk.Revit.UI.Result.Succeeded;
		}

		private void MergeSameWallInfo(ref List<UseData> lstInputData)
		{
			UseData item = default(UseData);
			List<UseData> list = new List<UseData>();
			List<UseData> list2 = new List<UseData>();
			for (int i = 0; i < lstInputData.Count; i++)
			{
				list.Add(lstInputData[i]);
				if (list.Count == 2)
				{
					Curve curve;
					if (this.IsNeedMerge(list[0], list[1], out curve))
					{
						if (curve != null)
						{
							item = lstInputData[i];
							item.line = (curve as Line);
						}
						list.Clear();
						list.Add(item);
						list2.AddRange(list);
					}
					else
					{
						list2.AddRange(list);
						if (list.Count != 1)
						{
							list.RemoveAt(0);
						}
					}
				}
			}
			for (int j = 0; j < list2.Count; j++)
			{
				Curve curve;
				if (j + 1 < list2.Count && this.IsNeedMerge(list2[j], list2[j + 1], out curve))
				{
					list2.RemoveAt(j);
					j--;
				}
			}
			lstInputData.Clear();
			lstInputData.AddRange(list2);
		}

		private bool IsNeedMerge(UseData oneData, UseData twoData, out Curve cv)
		{
			cv = null;
			if (oneData.wallTypeId == twoData.wallTypeId && oneData.strPurpose == twoData.strPurpose && oneData.strMaterial2FillName.Key == twoData.strMaterial2FillName.Key && oneData.location == twoData.location && oneData.strWallHeight == twoData.strWallHeight && oneData.strWallOffset == twoData.strWallOffset && GeoUtil.IsSameDirection(oneData.direction, twoData.direction))
			{
				cv = Line.CreateBound(oneData.line.GetEndPoint(0), twoData.line.GetEndPoint(1));
				return true;
			}
			return false;
		}

		private void GetWallHeight(UseData inputData, ref double dtempHeight)
		{
			KeyValuePair<Level, double> keyValuePair = default(KeyValuePair<Level, double>);
			KeyValuePair<Level, double> keyValuePair2 = default(KeyValuePair<Level, double>);
			this.GetAllLevels();
			Level upLevel = this.GetUpLevel(this.m_doc.ActiveView.GenLevel);
			if (inputData.strWallHeight == "当前层高")
			{
				if (upLevel != null && upLevel.Id.IntegerValue == this.m_doc.ActiveView.GenLevel.Id.IntegerValue)
				{
					dtempHeight = Common.MMToFeet(DataDefine.m_dDefaultWallHeight);
					this.m_TopLevel = this.m_doc.ActiveView.GenLevel;
					this.m_TopLevelOffsetVal = dtempHeight;
					return;
				}
				dtempHeight = upLevel.Elevation - this.m_doc.ActiveView.GenLevel.Elevation;
				this.m_TopLevel = upLevel;
				this.m_TopLevelOffsetVal = 0.0;
				return;
			}
			else
			{
				dtempHeight = Common.MMToFeet(double.Parse(inputData.strWallHeight));
				double num = this.m_doc.ActiveView.GenLevel.Elevation + dtempHeight;
				int i = 0;
				while (i < this.m_lstKvpLevel2Elevation.Count)
				{
					if (Geometry.LessThan(this.m_lstKvpLevel2Elevation.Last<KeyValuePair<Level, double>>().Value, num))
					{
						this.m_TopLevel = this.m_lstKvpLevel2Elevation.Last<KeyValuePair<Level, double>>().Key;
						this.m_TopLevelOffsetVal = num - this.m_lstKvpLevel2Elevation.Last<KeyValuePair<Level, double>>().Value;
						return;
					}
					if (!Geometry.LessThan(this.m_lstKvpLevel2Elevation[i].Value, num))
					{
						keyValuePair = this.m_lstKvpLevel2Elevation[i];
						if (i - 1 >= 0)
						{
							keyValuePair2 = this.m_lstKvpLevel2Elevation[i - 1];
							break;
						}
						break;
					}
					else
					{
						i++;
					}
				}
				double num2 = keyValuePair.Value - num;
				double num3 = num - keyValuePair2.Value;
				if (Geometry.LessThan(Math.Abs(num2), Math.Abs(num3)) || Geometry.IsEqual(Math.Abs(num2), Math.Abs(num3)))
				{
					this.m_TopLevel = keyValuePair.Key;
					this.m_TopLevelOffsetVal = -num2;
					return;
				}
				this.m_TopLevel = keyValuePair2.Key;
				this.m_TopLevelOffsetVal = num3;
				return;
			}
		}

		public List<Level> GetAllLevels()
		{
			List<Level> list = new List<Level>();
			foreach (ElementId elementId in new FilteredElementCollector(this.m_doc).OfClass(typeof(Level)).ToElementIds().ToList<ElementId>())
			{
				list.Add(this.m_doc.GetElement(elementId) as Level);
			}
			list.Sort(new LevelComparer());
			list.Reverse();
			foreach (Level level in list)
			{
				this.m_lstKvpLevel2Elevation.Add(new KeyValuePair<Level, double>(level, level.Elevation));
			}
			return list;
		}

		private Level GetUpLevel(Level CurLevel)
		{
			Level result = null;
			FilteredElementIterator elementIterator = new FilteredElementCollector(this.m_doc).OfClass(typeof(Level)).GetElementIterator();
			elementIterator.Reset();
			while (elementIterator.MoveNext())
			{
				Element element = elementIterator.Current;
				Level level = element as Level;
				if (level != null)
				{
					if (CurLevel.Elevation == level.Elevation)
					{
						result = level;
					}
					if (CurLevel.Elevation < level.Elevation)
					{
						result = level;
						break;
					}
				}
			}
			return result;
		}

		private XYZ getPointLoop(JigLineOperator thisOperator, YRevitJigExtend thisJig, DrawWallForm thisForm, ref List<UseData> lstUseData)
		{
			XYZ xyz = null;
			do
			{
				thisJig.SetJigInfo(thisForm.GetUseData());
				try
				{
					if (thisOperator.GetEndPoint() == null && this.bisEnd)
					{
						xyz = thisJig.PickStartPointEX("请选择一点，ESC结束");
					}
					else
					{
						thisJig.PickEndPointEX(thisOperator.GetEndPoint(), ref xyz, "请选择一点，ESC结束", false);
					}
				}
				catch (Exception)
				{
					if (thisOperator.GetEndPoint() != null && thisForm.m_isChangeMaterial)
					{
						this.bisEnd = false;
					}
					if (xyz == null)
					{
						throw;
					}
				}
				UseData useData = thisForm.GetUseData();
				if (xyz != null)
				{
					thisOperator.AddOnePoint(xyz, ref useData);
					if (useData.line != null)
					{
						lstUseData.Add(useData);
					}
				}
			}
			while (xyz != null);
			return xyz;
		}

		private List<WallType> GetAllWallTypes()
		{
			List<WallType> list = new List<WallType>();
			foreach (Element element in new FilteredElementCollector(this.m_doc).OfClass(typeof(WallType)).ToElements())
			{
				WallType wallType = element as WallType;
				if (wallType != null)
				{
					list.Add(wallType);
				}
			}
			return list;
		}

		private int GetLocationType(LocationCv inputType)
		{
			int result = 0;
			switch (inputType)
			{
			case LocationCv.WallCenter:
				result = 0;
				break;
			case LocationCv.CoreCenter:
				result = 1;
				break;
			case LocationCv.SurfaceLayerOuter:
				result = 2;
				break;
			case LocationCv.SurfaceLayerInner:
				result = 3;
				break;
			case LocationCv.CoreLayerOuter:
				result = 4;
				break;
			case LocationCv.CoreLayerInner:
				result = 5;
				break;
			}
			return result;
		}

		private int GetPurposeType(string inputType)
		{
			int result = 0;
			if (inputType == "内部")
			{
				result = 0;
			}
			else if (inputType == "外部")
			{
				result = 1;
			}
			else if (inputType == "基础墙")
			{
				result = 2;
			}
			else if (inputType == "挡土墙")
			{
				result = 3;
			}
			else if (inputType == "檐底板")
			{
				result = 4;
			}
			else if (inputType == "核心竖井")
			{
				result = 5;
			}
			return result;
		}

		private Document m_doc;

		private UIDocument m_uiDoc;

		private ExternalCommandData m_commandData;

		public static WindowHandle _hWndRevit;

		private bool bisEnd = true;

		private List<WallType> m_lstResWallType = new List<WallType>();

		private Level m_TopLevel;

		private double m_TopLevelOffsetVal;

		private List<KeyValuePair<Level, double>> m_lstKvpLevel2Elevation = new List<KeyValuePair<Level, double>>();
	}
}
